/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo
 * All rights reserved.
 */
package ac.jp.u_tokyo.SyncLib;

import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;

public class SetMembers extends StateSync
{
	public interface MembersTester
	{
		boolean isMembers(Object[] v);
		int getCount();
	}

	public static class NoDefaultValue{}
	
	private MembersTester _tester;
	private Object _defaults;

	public SetMembers(MembersTester tester, Object defaults)
	{
		super(new Object[tester.getCount()]);
		_tester = tester;
		_defaults = defaults;
	}

	public int getParaCount()
	{
		return _tester.getCount();
	}

	public Mod[] resynchronize(Object[] values, Mod[] modifications)
			throws SynchronizationFailedException
	{
		assert modifications.length == _tester.getCount();
		Object[] newValues = new Object[_tester.getCount()];
		Mod[] result = new Mod[_tester.getCount()];
		
		for(int i = 0; i < _tester.getCount(); i++) {
			assert modifications[i] != null;
			newValues[i] = modifications[i].apply(values[i]);
			result[i] = modifications[i];
		}

		if (!_tester.isMembers(newValues)) {
			if (_defaults instanceof NoDefaultValue)
				throw new SynchronizationFailedException();
			
			Object[] defaults = (Object[]) _defaults;
			for (int i = 0; i < defaults.length; i++)
			{
				newValues[i] = defaults[i];
				result[i] = Value2Mod.findMod(values[i], newValues[i]);
				if (result[i].isConflict(modifications[i])) 
					throw new SynchronizationFailedException();
				result[i] = result[i].merge(modifications[i]);
			}
		}
		for(int i = 0; i < _tester.getCount(); i++) {
			modifyAttribute(i, Value2Mod.findMod(getAttribute(i), newValues[i]));
		}
		return result;

	}

	public Mod[] synchronize(Mod[] modifications)
			throws SynchronizationFailedException
	{
		assert modifications.length == _tester.getCount();
		Object[] newValues = new Object[_tester.getCount()];
		
		for(int i = 0; i < _tester.getCount(); i++) {
			assert modifications[i] != null;
			newValues[i] = modifications[i].apply(getAttribute(i));
		}
		
		if (_tester.isMembers(newValues)) {
			for(int i = 0; i < _tester.getCount(); i++) {
				modifyAttribute(i, modifications[i]);
			}
			return modifications;
		}
		
		throw new SynchronizationFailedException();
	}

}
